package com.yc.cloud.openai.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.yc.cloud.basic.config.PathUtils;
import com.yc.cloud.basic.exception.Asserts;
import com.yc.cloud.basic.utils.MyFileConvertUtils;
import com.yc.cloud.basic.utils.MyFileUtils;
import com.yc.cloud.openai.constants.OpenAiConstants;
import com.yc.cloud.openai.dto.TTSResultDTO;
import com.yc.cloud.openai.dto.resp.XFNLPApiResp;
import com.yc.cloud.openai.request.TTSParam;
import com.yc.cloud.openai.service.tts.TTSService;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.codec.binary.Base64;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service("XFTTSServiceImpl")
public class XFTTSServiceImpl implements TTSService {


    private static final String URL = "http://openapi.xfyun.cn/v2/aiui";

    //191****3095 这个账号下的内容
    private static final String APPID = "a7f41698";
    private static final String API_KEY = "9380c45a5f97d55093401dcb844d008d";
    private static final String DATA_TYPE = "text";
    private static final String SCENE = "IFLYTEK.tts";
    private static final String SAMPLE_RATE = "16000";
    private static final String AUTH_ID = "2894c985bf8b1111c6728db79d3479ae";
    private static final String AUE = "raw";
    private static final String SUCCESS_CODE = "0";
    private final String SUB_TTS = "tts";

    @Override
    public TTSResultDTO getTTSResult(TTSParam param) {
        val ttsStart = System.currentTimeMillis();
        val header = buildHeader(param);
        String result = httpPost(header, param.getContent().getBytes(StandardCharsets.UTF_8));
        //log.debug("XFNLPApiServiceImpl getNLPResult---->{}", result);
        if (StrUtil.isEmpty(result)) {
            return null;
        }
        val xfnlpApiResp = JSONUtil.toBean(result, XFNLPApiResp.class);
        //响应失败
        if (!SUCCESS_CODE.equals(xfnlpApiResp.getCode())) {
            log.error("XFNLPApiServiceImpl ERROR--->{}", xfnlpApiResp.getDesc());
            Asserts.fail(xfnlpApiResp.getDesc());
        }
        val ttsResultDTO = new TTSResultDTO();
        val dataDTOList = xfnlpApiResp.getData();
        dataDTOList.forEach(dataDTO -> {
            val sub = dataDTO.getSub();
            if (SUB_TTS.equals(sub)) {
                //当前数据为pcm格式,使用ffmpeg将pcm数据转成wav,h5方便显示
                val pcmPath = Paths.get(PathUtils.getTempBasePath(), System.currentTimeMillis() + "-xf-tts.pcm").toString();
                MyFileUtils.decodeAndSaveFile(dataDTO.getContent(), pcmPath);
                val wavPath = pcmPath.replace(".pcm", ".wav");
                MyFileConvertUtils.pcm2wav(pcmPath, wavPath);
                val wavBase64Data = MyFileUtils.convertToBase64(FileUtil.file(wavPath));
                ttsResultDTO.setResult(wavBase64Data);
            }
        });
        val ttsEnd = System.currentTimeMillis();
        val costTime = ttsEnd - ttsStart;
        ttsResultDTO.setCostTime(costTime);
        return ttsResultDTO;
    }

    @Override
    public Mono<TTSResultDTO> getTTSResultByMono(TTSParam param) {
        val ttsResultDTO = getTTSResult(param);
        return Mono.just(ttsResultDTO);
    }


    private Map<String, String> buildHeader(TTSParam nlpParam) {
        String appKey = nlpParam.getAppKey();
        String appid = nlpParam.getAppid();
        if (StrUtil.isEmpty(appKey)) {
            appKey = API_KEY;
        }
        if (StrUtil.isEmpty(appid)) {
            appid = APPID;
        }
        String curTime = System.currentTimeMillis() / 1000L + "";
        // 使用 HashMap 构建参数
        Map<String, String> params = new HashMap<>();
        params.put("aue", AUE);
        params.put("sample_rate", SAMPLE_RATE);
        params.put("auth_id", AUTH_ID);
        params.put("data_type", DATA_TYPE);
        params.put("scene", SCENE);
        params.put("tts_aue", AUE);


//        var vcn = "x2_xiaojuan";
        if (OpenAiConstants.GENDER_MAN.equals(nlpParam.getGender())) {
            params.put("vcn", "x_qige");
        } else {
            params.put("vcn", "x2_xiaojuan");
        }
        String param = JSONUtil.toJsonStr(params);
        String paramBase64 = new String(Base64.encodeBase64(param.getBytes(StandardCharsets.UTF_8)));
        String checkSum = org.apache.commons.codec.digest.DigestUtils.md5Hex(appKey + curTime + paramBase64);

        Map<String, String> header = new HashMap<>();
        header.put("X-Param", paramBase64);
        header.put("X-CurTime", curTime);
        header.put("X-CheckSum", checkSum);
        header.put("X-Appid", appid);
        return header;
    }


    private String httpPost(Map<String, String> header, byte[] body) {
        StringBuilder result = new StringBuilder();
        BufferedReader in = null;
        OutputStream out = null;
        try {
            java.net.URL realUrl = new URL(URL);
            HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection();
            for (String key : header.keySet()) {
                connection.setRequestProperty(key, header.get(key));
            }
            connection.setDoOutput(true);
            connection.setDoInput(true);

            //connection.setConnectTimeout(20000);
            //connection.setReadTimeout(20000);
            try {
                out = connection.getOutputStream();
                out.write(body);
                out.flush();
            } catch (Exception e) {
                e.printStackTrace();
            }

            try {
                in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String line;
                while ((line = in.readLine()) != null) {
                    result.append(line);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result.toString();
    }
}
